"""
System Monitoring Agent Service

This service provides system monitoring functionality including:
- Conversation session statistics
- Recent activity monitoring
- Server load and performance metrics
- Database and system health checks
"""

import os
import psutil
import asyncio
import time
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
from sqlalchemy import func, desc, text
from sqlalchemy.orm import Session
from sqlalchemy.future import select

from app.core.database import get_sync_db, AsyncSessionLocal
from app.models.chat import Conversation, Message, MessageRole, ChatMode
from app.models.user import User
from app.core.config import settings
from app.core.redis import redis_client


class SystemAgent:
    """
    System monitoring agent for handling system-related queries
    """

    def __init__(self):
        self.redis_client = redis_client
        self.start_time = time.time()

    def get_system_info(self) -> Dict[str, Any]:
        """
        Get basic system information

        Returns:
            Dict: System information including CPU, memory, disk usage
        """
        try:
            # Get CPU usage
            cpu_percent = psutil.cpu_percent(interval=1)
            cpu_count = psutil.cpu_count()
            cpu_count_logical = psutil.cpu_count(logical=True)

            # Get memory usage
            memory = psutil.virtual_memory()
            swap = psutil.swap_memory()

            # Get disk usage
            disk = psutil.disk_usage('/')

            # Get system uptime
            uptime_seconds = time.time() - psutil.boot_time()
            uptime_days = uptime_seconds / (24 * 3600)

            # Get process info
            process = psutil.Process()
            process_memory = process.memory_info()
            process_cpu = process.cpu_percent()

            uname_info = os.uname()
            return {
                "timestamp": datetime.now().isoformat(),
                "system": {
                    "hostname": uname_info.nodename,
                    "platform": uname_info.sysname,
                    "platform_version": uname_info.release,
                    "uptime_days": round(uptime_days, 2)
                },
                "cpu": {
                    "usage_percent": cpu_percent,
                    "physical_cores": cpu_count,
                    "logical_cores": cpu_count_logical
                },
                "memory": {
                    "total_gb": round(memory.total / (1024**3), 2),
                    "available_gb": round(memory.available / (1024**3), 2),
                    "used_gb": round(memory.used / (1024**3), 2),
                    "usage_percent": memory.percent,
                    "swap_total_gb": round(swap.total / (1024**3), 2),
                    "swap_used_gb": round(swap.used / (1024**3), 2),
                    "swap_percent": swap.percent
                },
                "disk": {
                    "total_gb": round(disk.total / (1024**3), 2),
                    "free_gb": round(disk.free / (1024**3), 2),
                    "used_gb": round(disk.used / (1024**3), 2),
                    "usage_percent": round((disk.used / disk.total) * 100, 2)
                },
                "application": {
                    "uptime_hours": round((time.time() - self.start_time) / 3600, 2),
                    "memory_usage_mb": round(process_memory.rss / (1024**2), 2),
                    "cpu_usage_percent": process_cpu
                }
            }
        except Exception as e:
            return {"error": f"获取系统信息失败: {str(e)}"}

    def get_conversation_stats(self) -> Dict[str, Any]:
        """
        Get conversation statistics

        Returns:
            Dict: Conversation statistics including counts, recent activity
        """
        try:
            db = next(get_sync_db())

            # Total conversations
            total_conversations = db.scalar(select(func.count(Conversation.id)))

            # Conversations by mode
            conversations_by_mode = {}
            for mode in ChatMode:
                count = db.scalar(
                    select(func.count(Conversation.id))
                    .where(Conversation.chat_mode == mode)
                )
                conversations_by_mode[mode.value] = count

            # Recent conversations (last 24 hours)
            yesterday = datetime.now() - timedelta(days=1)
            recent_conversations = db.scalar(
                select(func.count(Conversation.id))
                .where(Conversation.created_at >= yesterday)
            )

            # Total messages
            total_messages = db.scalar(select(func.count(Message.id)))

            # Messages by role
            messages_by_role = {}
            for role in MessageRole:
                count = db.scalar(
                    select(func.count(Message.id))
                    .where(Message.role == role)
                )
                messages_by_role[role.value] = count

            # Recent messages (last hour)
            one_hour_ago = datetime.now() - timedelta(hours=1)
            recent_messages = db.scalar(
                select(func.count(Message.id))
                .where(Message.created_at >= one_hour_ago)
            )

            # Get most recent conversation
            latest_conversation = db.execute(
                select(Conversation)
                .order_by(desc(Conversation.created_at))
                .limit(1)
            ).scalar_one_or_none()

            # Get active users (users with conversations in last 7 days)
            week_ago = datetime.now() - timedelta(days=7)
            active_users = db.scalar(
                select(func.count(func.distinct(Conversation.user_id)))
                .where(Conversation.created_at >= week_ago)
                .where(Conversation.user_id.isnot(None))
            )

            db.close()

            return {
                "timestamp": datetime.now().isoformat(),
                "conversations": {
                    "total": total_conversations,
                    "recent_24h": recent_conversations,
                    "by_mode": conversations_by_mode
                },
                "messages": {
                    "total": total_messages,
                    "recent_1h": recent_messages,
                    "by_role": messages_by_role
                },
                "users": {
                    "active_7d": active_users
                },
                "latest_activity": {
                    "latest_conversation": {
                        "id": latest_conversation.id,
                        "title": latest_conversation.title,
                        "created_at": latest_conversation.created_at.isoformat() if latest_conversation else None,
                        "chat_mode": latest_conversation.chat_mode.value if latest_conversation else None
                    } if latest_conversation else None
                }
            }
        except Exception as e:
            return {"error": f"获取会话统计失败: {str(e)}"}

    def get_recent_conversations(self, limit: int = 10) -> List[Dict[str, Any]]:
        """
        Get recent conversations with details

        Args:
            limit: Maximum number of conversations to return

        Returns:
            List[Dict]: Recent conversations with summary information
        """
        try:
            db = next(get_sync_db())

            # Get recent conversations
            conversations = db.execute(
                select(Conversation)
                .order_by(desc(Conversation.created_at))
                .limit(limit)
            ).scalars().all()

            result = []
            for conv in conversations:
                # Get message count for this conversation
                message_count = db.scalar(
                    select(func.count(Message.id))
                    .where(Message.conversation_id == conv.id)
                )

                # Get latest message
                latest_message = db.execute(
                    select(Message)
                    .where(Message.conversation_id == conv.id)
                    .order_by(desc(Message.created_at))
                    .limit(1)
                ).scalar_one_or_none()

                conv_info = {
                    "id": conv.id,
                    "title": conv.title,
                    "chat_mode": conv.chat_mode.value,
                    "user_id": conv.user_id,
                    "created_at": conv.created_at.isoformat(),
                    "updated_at": conv.updated_at.isoformat(),
                    "message_count": message_count,
                    "latest_message": {
                        "content": latest_message.content[:100] + "..." if latest_message and len(latest_message.content) > 100 else (latest_message.content if latest_message else None),
                        "role": latest_message.role.value if latest_message else None,
                        "created_at": latest_message.created_at.isoformat() if latest_message else None
                    }
                }

                result.append(conv_info)

            db.close()
            return result

        except Exception as e:
            return [{"error": f"获取最近会话失败: {str(e)}"}]

    def get_database_health(self) -> Dict[str, Any]:
        """
        Get database health and performance metrics

        Returns:
            Dict: Database health information
        """
        try:
            db = next(get_sync_db())

            # Test database connection
            start_time = time.time()
            db.execute(text("SELECT 1"))
            connection_time = (time.time() - start_time) * 1000  # Convert to milliseconds

            # Get table counts
            table_counts = {}
            tables = ["conversations", "messages", "users", "conversation_summaries"]
            for table in tables:
                try:
                    count = db.scalar(text(f"SELECT COUNT(*) FROM {table}"))
                    table_counts[table] = count
                except Exception:
                    table_counts[table] = 0

            # Get database size (SQLite specific)
            try:
                db_size_result = db.execute(text("SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()")).scalar_one()
                db_size_mb = db_size_result / (1024 * 1024)
            except Exception:
                db_size_mb = 0

            db.close()

            return {
                "timestamp": datetime.now().isoformat(),
                "connection": {
                    "status": "healthy",
                    "response_time_ms": round(connection_time, 2)
                },
                "tables": table_counts,
                "size_mb": round(db_size_mb, 2)
            }

        except Exception as e:
            return {
                "timestamp": datetime.now().isoformat(),
                "connection": {
                    "status": "error",
                    "error": str(e)
                },
                "tables": {},
                "size_mb": 0
            }

    def get_redis_health(self) -> Dict[str, Any]:
        """
        Get Redis health and performance metrics

        Returns:
            Dict: Redis health information
        """
        try:
            if not self.redis_client or not self.redis_client.redis:
                return {
                    "timestamp": datetime.now().isoformat(),
                    "status": "disabled",
                    "message": "Redis is not configured"
                }

            # Test Redis connection
            start_time = time.time()
            import asyncio
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            try:
                loop.run_until_complete(self.redis_client.ping())
                response_time = (time.time() - start_time) * 1000

                # Get Redis info
                info = loop.run_until_complete(self.redis_client.redis.info())
            finally:
                loop.close()

            return {
                "timestamp": datetime.now().isoformat(),
                "status": "healthy",
                "response_time_ms": round(response_time, 2),
                "memory_used_mb": round(info.get("used_memory", 0) / (1024 * 1024), 2),
                "memory_peak_mb": round(info.get("used_memory_peak", 0) / (1024 * 1024), 2),
                "connected_clients": info.get("connected_clients", 0),
                "total_commands_processed": info.get("total_commands_processed", 0),
                "uptime_days": round(info.get("uptime_in_seconds", 0) / (24 * 3600), 2)
            }

        except Exception as e:
            return {
                "timestamp": datetime.now().isoformat(),
                "status": "error",
                "error": str(e)
            }

    def get_performance_metrics(self) -> Dict[str, Any]:
        """
        Get application performance metrics

        Returns:
            Dict: Performance metrics and statistics
        """
        try:
            # Get process metrics
            process = psutil.Process()

            # Get thread count
            thread_count = process.num_threads()

            # Get open file descriptors
            try:
                open_files = process.num_handles() if hasattr(process, 'num_handles') else process.num_fds()
            except Exception:
                open_files = 0

            # Get I/O counters
            try:
                io_counters = process.io_counters()
                io_stats = {
                    "read_bytes": io_counters.read_bytes,
                    "write_bytes": io_counters.write_bytes,
                    "read_count": io_counters.read_count,
                    "write_count": io_counters.write_count
                }
            except Exception:
                io_stats = {}

            # Get network connections
            try:
                connections = len(process.connections())
            except Exception:
                connections = 0

            return {
                "timestamp": datetime.now().isoformat(),
                "process": {
                    "thread_count": thread_count,
                    "open_files": open_files,
                    "network_connections": connections
                },
                "io": io_stats,
                "application": {
                    "uptime_hours": round((time.time() - self.start_time) / 3600, 2)
                }
            }

        except Exception as e:
            return {"error": f"获取性能指标失败: {str(e)}"}

    def generate_system_report(self) -> str:
        """
        Generate a comprehensive system report

        Returns:
            str: Formatted system report
        """
        try:
            # Collect all system information
            system_info = self.get_system_info()
            conversation_stats = self.get_conversation_stats()
            database_health = self.get_database_health()
            redis_health = self.get_redis_health()
            performance_metrics = self.get_performance_metrics()

            # Format the report
            report = f"""
🖥️ 系统监控报告
生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

📊 系统资源
- CPU使用率: {system_info.get('cpu', {}).get('usage_percent', 0)}%
- 内存使用率: {system_info.get('memory', {}).get('usage_percent', 0)}%
- 磁盘使用率: {system_info.get('disk', {}).get('usage_percent', 0)}%
- 系统运行时间: {system_info.get('system', {}).get('uptime_days', 0)}天

💬 会话统计
- 总会话数: {conversation_stats.get('conversations', {}).get('total', 0)}
- 24小时内会话: {conversation_stats.get('conversations', {}).get('recent_24h', 0)}
- 总消息数: {conversation_stats.get('messages', {}).get('total', 0)}
- 1小时内消息: {conversation_stats.get('messages', {}).get('recent_1h', 0)}
- 7天活跃用户: {conversation_stats.get('users', {}).get('active_7d', 0)}

🗄️ 数据库状态
- 连接状态: {database_health.get('connection', {}).get('status', 'unknown')}
- 响应时间: {database_health.get('connection', {}).get('response_time_ms', 0)}ms
- 数据库大小: {database_health.get('size_mb', 0)}MB

🔥 Redis缓存
- 状态: {redis_health.get('status', 'unknown')}
- 响应时间: {redis_health.get('response_time_ms', 0)}ms
- 内存使用: {redis_health.get('memory_used_mb', 0)}MB

⚡ 应用性能
- 线程数: {performance_metrics.get('process', {}).get('thread_count', 0)}
- 打开文件数: {performance_metrics.get('process', {}).get('open_files', 0)}
- 网络连接数: {performance_metrics.get('process', {}).get('network_connections', 0)}
- 应用运行时间: {performance_metrics.get('application', {}).get('uptime_hours', 0)}小时
            """.strip()

            return report

        except Exception as e:
            return f"生成系统报告失败: {str(e)}"

    def handle_system_query(self, query: str) -> str:
        """
        Handle system-related queries with natural language understanding

        Args:
            query: User's system-related query

        Returns:
            str: Response to the query
        """
        query_lower = query.lower()

        # Handle different types of system queries
        if any(keyword in query_lower for keyword in ['会话', '对话', 'conversation']):
            if any(keyword in query_lower for keyword in ['多少', '数量', '统计']):
                stats = self.get_conversation_stats()
                if "error" in stats:
                    return stats["error"]

                return f"""
💬 当前会话统计:
- 总会话数: {stats.get('conversations', {}).get('total', 0)}
- 24小时内新增会话: {stats.get('conversations', {}).get('recent_24h', 0)}
- 总消息数: {stats.get('messages', {}).get('total', 0)}
- 1小时内消息: {stats.get('messages', {}).get('recent_1h', 0)}
- 7天活跃用户: {stats.get('users', {}).get('active_7d', 0)}
                """.strip()

            elif any(keyword in query_lower for keyword in ['最近', '最新', 'recent']):
                recent = self.get_recent_conversations(5)
                if "error" in recent[0]:
                    return recent[0]["error"]

                result = "📋 最近5个会话:\n\n"
                for conv in recent[:5]:
                    result += f"""
📝 {conv['title']} (ID: {conv['id']})
- 模式: {conv['chat_mode']}
- 消息数: {conv['message_count']}
- 创建时间: {conv['created_at'][:19]}
- 最新消息: {conv['latest_message']['content'][:50]}...
                    """.strip() + "\n\n"

                return result.strip()

        elif any(keyword in query_lower for keyword in ['服务器', '负载', '系统', 'system']):
            if any(keyword in query_lower for keyword in ['负载', 'load', '性能']):
                system_info = self.get_system_info()
                if "error" in system_info:
                    return system_info["error"]

                return f"""
⚡ 系统负载情况:
- CPU使用率: {system_info.get('cpu', {}).get('usage_percent', 0)}%
- 内存使用率: {system_info.get('memory', {}).get('usage_percent', 0)}%
- 磁盘使用率: {system_info.get('disk', {}).get('usage_percent', 0)}%
- 应用内存使用: {system_info.get('application', {}).get('memory_usage_mb', 0)}MB
- 应用CPU使用: {system_info.get('application', {}).get('cpu_usage_percent', 0)}%
                """.strip()

        elif any(keyword in query_lower for keyword in ['报告', 'report', '概览', 'overview']):
            return self.generate_system_report()

        elif any(keyword in query_lower for keyword in ['数据库', 'database']):
            db_health = self.get_database_health()
            redis_health = self.get_redis_health()

            return f"""
🗄️ 数据库状态:
- 连接状态: {db_health.get('connection', {}).get('status', 'unknown')}
- 响应时间: {db_health.get('connection', {}).get('response_time_ms', 0)}ms
- 数据库大小: {db_health.get('size_mb', 0)}MB

🔥 Redis状态:
- 状态: {redis_health.get('status', 'unknown')}
- 响应时间: {redis_health.get('response_time_ms', 0)}ms
- 内存使用: {redis_health.get('memory_used_mb', 0)}MB
            """.strip()

        else:
            # Default to full system report
            return self.generate_system_report()


# Global system agent instance
system_agent = SystemAgent()


def handle_system_query(query: str) -> str:
    """
    Convenience function to handle system queries

    Args:
        query: User's system-related query

    Returns:
        str: Response to the query
    """
    return system_agent.handle_system_query(query)